﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.SqlClient;
using System.Data;
using TSL_Tools.SqlTools;
using ReportingEngine;
using System.IO;
using System.Windows.Forms.DataVisualization.Charting;
using System.Xml;
using System.ComponentModel;

namespace VSLT_Reporting
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region -- SQL QUERY String Constants ---------------------------------------------------------------------------------

        #region -- Core Table Queries ------------------------------------------
        public static readonly string Sql_GETSCORECARDSUMMARYTABLE = @"
SELECT 
	  [LoadTestRunId]
      ,[LoadTestName]
      ,[Description]
      ,[StartTime]
      ,[RunDuration]
      ,[TotalTests]
      ,[PassedTests]
      ,[FailedTests]
      ,[AvgTT_All]
      ,[TestsSec_All]
      ,[TotalTrans]
      ,[AvgTrET_All]
      ,[AvgTrRT_All]
      ,[TransSec_All]
      ,[TotalPages]
      ,[PagesSec_All]
      ,[AvgPgT_All]
      ,[TotalRequests]
      ,[PassedRequests]
      ,[FailedRequests]
      ,[CachedRequests]
      ,[ReqSec_All]
      ,[AvgReqT_All]
      ,[AvgReqLen_All]
      ,[EndTime]
      ,[WarmupTime]
      ,[MaxUsers]
      ,[RunSettingUsed]
      ,[IsLocalRun]
      ,[ControllerName]
      ,[Outcome]
      ,[CooldownTime]
      ,[AgentCount]
FROM MTSL_View_LoadTestSummary
WHERE LoadTestRunId IN ({0})
";

        public static readonly string Sql_GETSCORECARDCPUTABLE = @"
SELECT 
	  [LoadTestRunId]
      ,[MachineName]
      ,[Qty]
      ,[Min]
      ,[Avg]
      ,[Max]
FROM TSL_ScoreCardMachineCPU
WHERE LoadTestRunId IN ({0})
ORDER BY LoadTestRunId, MachineName ASC        
";

        #endregion

        /// <summary>
        /// Parameter 0: columnToPlot
        /// Parameter 1: list of runs
        /// Parameter 2: machine
        /// </summary>
        public static readonly string Sql_GETSCORECARDCPUCHART = @"
SELECT 
	LoadTestRunId
	,CAST(AVG([{0}]) AS Decimal(15,2)) AS [{0}]
FROM TSL_ScoreCardMachineCPU 
WHERE LoadTestRunId IN ({1})
AND MachineName LIKE '{2}'
GROUP BY LoadTestRunId ORDER BY LoadTestRunId ASC
";


        /// <summary>
        /// Parameter 0: columnToPlot
        /// Parameter 1: list of runs
        /// </summary>
        public static readonly string Sql_GETSCORECARDTHROUGHPUTCHART = @"
SELECT
	LoadTestRunId,
	{0}  
FROM TSL_LoadTestCoreInfo
WHERE LoadTestRunId IN ({1})
ORDER BY LoadTestRunId ASC
";

        /// <summary>
        /// Parameter 0: list of runs
        /// Parameter 1: machine
        /// </summary>

        public static readonly string Sql_GETSCORECARDMEMORYTABLE = @"
SELECT 
    [LoadTestRunId]
	,CAST(AVG([Min]) AS Decimal(15,2)) AS [Min]
	,CAST(AVG([Avg]) AS Decimal(15,2)) AS [Avg]
	,CAST(AVG([Max]) AS Decimal(15,2)) AS [Max]
FROM TSL_ScoreCardMachineAvailableMB
WHERE LoadTestRunId IN ({0})
AND MachineName LIKE '{1}'
GROUP BY LoadTestRunId
ORDER BY LoadTestRunId ASC
";

        public static readonly string Sql_GETSCORECARDPAGECOMPARISONTABLE = @"
EXEC	VSLT_prc_Page_Multirun_Comparison
		@RunIds = N'{0}',
		@ComparisonColumn = N'{1}'
";
        #endregion



        #region -- Scorecard Combo Chart methods -------------------------------------------------------------------------------------------
        public void GetAllScorecardComboCharts(bool bAddToReport)
        {
            DateTime dt = DateTime.Now;
            plotColors.Clear();
            GetChartObjectColorsFromXmlFile();

            string listOfHighlightedRuns = "";
            for (int x = 0; x < selectedRuns.Count; x++)
            {
                if (x < (selectedRuns.Count - 1))
                    listOfHighlightedRuns = listOfHighlightedRuns + selectedRuns[x].ToString() + ",";
                else
                    listOfHighlightedRuns = listOfHighlightedRuns + selectedRuns[x].ToString();
            }

            try
            {
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(Properties.Settings.Default.ChartObjectFileName);

                #region -- Scorecard Charts ----------------------------------------------------------------------
                foreach (XmlNode xNode in xDoc.GetElementsByTagName("ScoreCardChartSets"))
                {
                    foreach (XmlNode xChild in xNode.ChildNodes)
                    {
                        if (xChild.Attributes["enabled"].Value.ToLower() == "true")
                        {
                            Chart chart = this.FindName("MyWinformChart") as Chart;
                            LoadChartTemplate(ref chart, xChild.Attributes["template"].Value);
                            chart.Titles[0].Text = xChild.Attributes["name"].Value;
                            ClearChartObjectList();

                            foreach (XmlNode xChild2 in xChild.ChildNodes)
                            {
                                if (xChild2.Attributes["enabled"].Value.ToLower() == "true" &&
                                    xChild2.Attributes["type"].Value == "ScoreCardColumnCounter")
                                {
                                    AddScorecardCpuChartObjectsToTable(ref chart,
                                        xChild2.Attributes["name"].Value,
                                        xChild2.Attributes["color"].Value,
                                        xChild2.Attributes["type"].Value,
                                        xChild2.Attributes["columnToPlot"].Value,
                                        listOfHighlightedRuns,
                                        xChild2.Attributes["machine"].Value);
                                }
                                else if (xChild2.Attributes["enabled"].Value.ToLower() == "true" &&
                                    xChild2.Attributes["type"].Value == "ScoreCardLineCounter")
                                {
                                    AddScorecardThroughputChartObjectsToTable(ref chart,
                                        xChild2.Attributes["name"].Value,
                                        xChild2.Attributes["color"].Value,
                                        xChild2.Attributes["type"].Value,
                                        xChild2.Attributes["columnToPlot"].Value,
                                        listOfHighlightedRuns);
                                    if (xChild2.Attributes["ShowGoal"].Value.ToLower() == "true")
                                    {
                                        bool higherIsBetter = (xChild2.Attributes["HigherIsBetter"].Value.ToLower() == "true") ? true : false;

                                        AddScorecardGoalObjectToChart(ref chart, xChild2.Attributes["columnToPlot"].Value
                                            , "SandyBrown", xChild2.Attributes["Goal"].Value, higherIsBetter);
                                    }
                                }
                                else if (xChild2.Attributes["enabled"].Value.ToLower() == "true" &&
                                    xChild2.Attributes["type"].Value == "ScoreCardStackedColumnCounter")
                                {
                                    AddScorecardMemoryObjectsToTable(ref chart,
                                        xChild2.Attributes["name"].Value,
                                        xChild2.Attributes["color"].Value,
                                        xChild2.Attributes["type"].Value,
                                        listOfHighlightedRuns,
                                        xChild2.Attributes["machine"].Value);
                                }
                            }
                            //AddScorecardFailureRateAnnotations(ref chart);
                            if (bAddToReport)
                                AddCurrentChartToReport();
                        }
                    }
                }
                #endregion

                #region -- Scorecard Graphs ----------------------------------------------------------------------
  //<ScoreCardGraphSets>
  //  <chart name="CPU Comparison" enabled="true" template="Templates\chartTemplateWithLegend.xml" title="Processor Comparison {0}" axisLabel="%" machineList="'LABSYNC01','LABSYNC02','LABCSRS01','LABSQL01'" fixedscale="100" />
  //</ScoreCardGraphSets>
                foreach (XmlNode xNode in xDoc.GetElementsByTagName("ScoreCardGraphSets"))
                {
                    foreach (XmlNode xChild in xNode.ChildNodes)
                    {
                        if (xChild.Attributes["enabled"].Value.ToLower() == "true")
                        {
                            foreach (string str in xChild.Attributes["machineList"].Value.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries))
                            {
                                Chart chart = this.FindName("MyWinformChart") as Chart;
                                LoadChartTemplate(ref chart, xChild.Attributes["template"].Value);
                                chart.Titles[0].Text = String.Format(xChild.Attributes["title"].Value, str);
                                ClearChartObjectList();
                                int itemsToGraph = AddScoreCardGraphs(ref chart,
                                    listOfHighlightedRuns,
                                    str,
                                    xChild.Attributes["category"].Value,
                                    xChild.Attributes["counter"].Value,
                                    xChild.Attributes["instance"].Value);
                                if (itemsToGraph > 0 && bAddToReport)
                                    AddCurrentChartToReport();
                            }
                        }
                    }
                }
                #endregion
            }
            catch (XmlException ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

        private void AddScorecardCpuChartObjectsToTable(ref Chart chart, string name, string color, string seriesType, string columnToPlot, string listOfRuns, string machine)
        {
            /// <summary>
            /// Parameter 0: columnToPlot
            /// Parameter 1: list of runs
            /// Parameter 2: machine
            /// </summary>
            //public static readonly string Sql_GETSCORECARDCPUCHART = @"
            DataTable table = new DataTable();
            string sqlConn = Properties.Settings.Default.sqlConn;
            string sqlCmd = String.Format(Sql_GETSCORECARDCPUCHART, columnToPlot, listOfRuns, machine);
            tts.ExecuteReaderTable(sqlCmd, out table);

            Series series = new Series();
            series.ChartType = SeriesChartType.Column;
            series.Color = (System.Drawing.Color)TypeDescriptor.GetConverter(typeof(System.Drawing.Color)).ConvertFromString(color);
            series.Name = name;

            for (int x = 0; x < table.Rows.Count; x++)
            {
                series.Points.Add(new DataPoint
                {
                    AxisLabel = "Run " + table.Rows[x][0].ToString(),
                    YValues = new double[] { Convert.ToDouble(table.Rows[x][1]) }
                });
            }
            chart.Series.Add(series);
        }

        private void AddScorecardThroughputChartObjectsToTable(ref Chart chart, string name, string color, string seriesType, string columnToPlot, string listOfRuns)
        {
            /// <summary>
            /// Parameter 0: columnToPlot
            /// Parameter 1: list of runs
            /// Parameter 2: machine
            /// </summary>
            //public static readonly string Sql_GETSCORECARDCPUCHART = @"
            DataTable table = new DataTable();
            string sqlConn = Properties.Settings.Default.sqlConn;
            string sqlCmd = String.Format(Sql_GETSCORECARDTHROUGHPUTCHART, columnToPlot, listOfRuns);
            tts.ExecuteReaderTable(sqlCmd, out table);

            Series series = new Series();
            series.ChartType = SeriesChartType.Line;
            series.Color = (System.Drawing.Color)TypeDescriptor.GetConverter(typeof(System.Drawing.Color)).ConvertFromString(color);
            series.Name = String.Format("{0} {1}",name, columnToPlot);
            series.YAxisType = AxisType.Secondary;
            series.Label = "#VAL";
            series.Font = new System.Drawing.Font("Calibri", 22, System.Drawing.FontStyle.Bold);
            series.BorderWidth = 3;
            series.MarkerStyle = MarkerStyle.Circle;
            series.MarkerSize = 6;
            series.MarkerColor = System.Drawing.Color.Black;
            series.LabelBackColor = System.Drawing.Color.Beige;

            for (int x = 0; x < table.Rows.Count; x++)
            {
                series.Points.Add(new DataPoint
                {
                    AxisLabel = "Run " + table.Rows[x][0].ToString(),
                    YValues = new double[] { Convert.ToDouble(table.Rows[x][1]) }
                });
            }
            chart.Series.Add(series);
            chart.ChartAreas[0].AxisY2.Title = name;
        }

        private void AddScorecardMemoryObjectsToTable(ref Chart chart, string name, string color, string seriesType, string listOfRuns, string machine)
        {
            /// <summary>
            /// Parameter 0: columnToPlot
            /// Parameter 1: list of runs
            /// Parameter 2: machine
            /// </summary>
            //public static readonly string Sql_GETSCORECARDCPUCHART = @"
            DataTable table = new DataTable();
            string sqlConn = Properties.Settings.Default.sqlConn;
            string sqlCmd = String.Format(Sql_GETSCORECARDMEMORYTABLE, listOfRuns, machine);
            tts.ExecuteReaderTable(sqlCmd, out table);

            //Add Minimum Values first
            Series series = new Series();
            series.ChartType = SeriesChartType.StackedColumn;
            series.Color = System.Drawing.Color.Red;
            series.Name = name + "_Min";
            series["StackedGroupName"] = name + "_Stack";

            for (int x = 0; x < table.Rows.Count; x++)
            {
                series.Points.Add(new DataPoint
                {
                    AxisLabel = "Run " + table.Rows[x][0].ToString(),
                    YValues = new double[] { Convert.ToDouble(table.Rows[x][1]) }
                });
            }
            chart.Series.Add(series);

            
            //Add Average Values first
            series = new Series();
            series.ChartType = SeriesChartType.StackedColumn;
            series.Color = (System.Drawing.Color)TypeDescriptor.GetConverter(typeof(System.Drawing.Color)).ConvertFromString(color);
            series.Name = name + "_Avg";
            series["StackedGroupName"] = name + "_Stack";

            for (int x = 0; x < table.Rows.Count; x++)
            {
                series.Points.Add(new DataPoint
                {
                    AxisLabel = "Run " + table.Rows[x][0].ToString(),
                    YValues = new double[] { Convert.ToDouble(table.Rows[x][1]) }
                });
            }
            chart.Series.Add(series);

            
            //Add Minimum Values first
            series = new Series();
            series.ChartType = SeriesChartType.StackedColumn;
            series.Color = System.Drawing.Color.LightGreen;
            series.Name = name + "_Max";
            series["StackedGroupName"] = name + "_Stack";

            for (int x = 0; x < table.Rows.Count; x++)
            {
                series.Points.Add(new DataPoint
                {
                    AxisLabel = "Run " + table.Rows[x][0].ToString(),
                    YValues = new double[] { Convert.ToDouble(table.Rows[x][1]) }
                });
            }
            chart.Series.Add(series);
        }

        private void AddScoreCardCPUGraphs(ref Chart chart, string listOfRuns, string machine)
        {
            DataTable table = new DataTable();
            string sqlConn = Properties.Settings.Default.sqlConn;
            string sqlCmd = String.Format(@"SELECT LoadTestRunId, InstanceId FROM TSL_ScoreCardMachineCPU 
                WHERE MachineName = {0} AND LoadTestRunId IN ({1})"
                , machine, listOfRuns);
            tts.ExecuteReaderTable(sqlCmd, out table);
            currentPlotColor = 0;
            
            for (int x = 0; x < table.Rows.Count; x++)
            {
                string sqlCmd2 = String.Format("EXEC TSL_prc_PerfCounterValuesByInstanceId @RunId = {0}, @InstanceId = {1}"
                    , table.Rows[x][0], table.Rows[x][1]);
                DataTable _table;
                TimeSpan ts = tts.ExecuteReaderTable(sqlCmd2, out _table);
                AddDebugTimingInfo(ts, " --\tScoreCardGraphItems " + sqlCmd2);
                mostRecentSqlQuery = sqlCmd2;

                TSL_ChartingDataSeries series = new TSL_ChartingDataSeries();
                series.runId = currentlyHighlightedRunId;
                series.fullCounterName = String.Format("Run {0}", table.Rows[x][0]);
                series.name = "Avg. CPU";
                series.machineName = machine;
                series.categoryName = "Processor";
                series.counterName = "% Processor Time";
                series.instanceName = "_Total";
                series.lineColor = plotColors[currentPlotColor % plotColors.Count];
                series.chartObjectScale = 100;
                series.intervalSpan = re.listOfRuns[currentlyHighlightedRunId].sampleRate;
                currentPlotColor++;
                series.testIntervalValues = _table.Copy();
                AddChartSeriesItems(series, String.Format("Run{0}",table.Rows[x][0]));
            }

        }

        private int AddScoreCardGraphs(ref Chart chart, string listOfRuns, string machine, string category, string counter, string instance)
        {
            DataTable table = new DataTable();
            string sqlConn = Properties.Settings.Default.sqlConn;
            string sqlCmd;
            if (instance == "%")
            {
                sqlCmd = String.Format(@"SELECT LoadTestRunId, InstanceId FROM MTSL_View_PerfmonInstanceNamesAndIds
  WHERE CategoryName = '{0}' AND CounterName = '{1}'
  AND MachineName = {2} AND LoadTestRunId IN ({3})", category, counter, machine, listOfRuns);
            }
            else if (instance.Contains("%"))
            {
                sqlCmd = String.Format(@"SELECT LoadTestRunId, InstanceId FROM MTSL_View_PerfmonInstanceNamesAndIds
  WHERE CategoryName = '{0}' AND CounterName = '{1}' AND Instance LIKE '{2}'
  AND MachineName = {3} AND LoadTestRunId IN ({4})", category, counter, instance, machine, listOfRuns);
            }
            else
            {
                sqlCmd = String.Format(@"SELECT LoadTestRunId, InstanceId FROM MTSL_View_PerfmonInstanceNamesAndIds
  WHERE CategoryName = '{0}' AND CounterName = '{1}' AND Instance = '{2}'
  AND MachineName = {3} AND LoadTestRunId IN ({4})", category, counter, instance, machine, listOfRuns);
            }
            tts.ExecuteReaderTable(sqlCmd, out table);
            currentPlotColor = 0;
              
            for (int x = 0; x < table.Rows.Count; x++)
            {
                string sqlCmd2 = String.Format("EXEC TSL_prc_PerfCounterValuesByInstanceId @RunId = {0}, @InstanceId = {1}"
                    , table.Rows[x][0], table.Rows[x][1]);
                DataTable _table;
                TimeSpan ts = tts.ExecuteReaderTable(sqlCmd2, out _table);
                AddDebugTimingInfo(ts, " --\tScoreCardGraphItems " + sqlCmd2);
                mostRecentSqlQuery = sqlCmd2;

                TSL_ChartingDataSeries series = new TSL_ChartingDataSeries();
                series.runId = currentlyHighlightedRunId;
                series.fullCounterName = String.Format("Run {0}", table.Rows[x][0]);
                series.name = "Avg. CPU";
                series.machineName = machine;
                series.categoryName = "Processor";
                series.counterName = "% Processor Time";
                series.instanceName = "_Total";
                series.lineColor = plotColors[currentPlotColor % plotColors.Count];
                series.chartObjectScale = 100;
                series.intervalSpan = re.listOfRuns[currentlyHighlightedRunId].sampleRate;
                currentPlotColor++;
                series.testIntervalValues = _table.Copy();
                AddChartSeriesItems(series, String.Format("Run{0}", table.Rows[x][0]));
            }
            return table.Rows.Count;
        }
        #endregion

        #region -- Scorecard Single Chart methods ------------------------------------------------------------------------------------------
        private bool BuildScorecardSingleItemChart(ScoreCardItem item)
        {
            if (!item.ShowGraph)
                return false;

            bool chartHasData = false;
            Chart chart = this.FindName("MyWinformChart") as Chart;
            LoadChartTemplate(ref chart, "Templates\\ScoreCard_Chart_Template.xml");

            chart.Titles[0].Text = item.Title;
            chart.ChartAreas[0].AxisY.Title = item.Name;
            if (item.YAxisMax == 100)
            {
                chart.ChartAreas[0].AxisY.Maximum = 100;
            }
            switch (item.DataType.ToLower())
            {
                case "int":
                    List<int?> intList = GetScoreCardIntListForCharting(item.Name);
                    foreach (int? x in intList)
                    {
                        if (x != null)
                        {
                            chart.Series[0].Points.DataBindXY(GetScoreCardIntListForCharting("RunId"), intList);
                            chartHasData = true;
                            break;
                        }
                    }
                    break;

                case "double":
                    List<double?> doubleList = GetScoreCardDoubleListForCharting(item.Name);
                    foreach (double? x in doubleList)
                    {
                        if (x != null)
                        {
                            chart.Series[0].Points.DataBindXY(GetScoreCardIntListForCharting("RunId"), doubleList);
                            chartHasData = true;
                            break;
                        }
                    }
                    break;

                case "single":
                    List<Single?> singleList = GetScoreCardSingleListForCharting(item.Name);
                    foreach (double? x in singleList)
                    {
                        if (x != null)
                        {
                            chart.Series[0].Points.DataBindXY(GetScoreCardIntListForCharting("RunId"), singleList);
                            chartHasData = true;
                            break;
                        }
                    }
                    break;

                case "string":
                    List<string> stringList = GetScoreCardStringListForCharting(item.Name);
                    chartHasData = true;
                    chart.Series[0].Points.DataBindXY(GetScoreCardIntListForCharting("RunId"), stringList);
                    break;
            }
            if(item.ShowGoal)
            {
                AddScorecardGoalObjectToChart(ref chart, item.Name, System.Drawing.Color.Green, item.Goal, item.HigherIsBetter, true);
            }
            return chartHasData;
        }

        private List<int?> GetScoreCardIntListForCharting(string column)
        {
            List<int?> _list = new List<int?>();

            for (int x = 0; x < _scoreCardMetrics.Rows.Count; x++)
            {
                object ID = _scoreCardMetrics.Rows[x][column];
                if (ID != null && !String.IsNullOrEmpty(ID.ToString().Trim()))
                    _list.Add((int)ID);
                else
                    _list.Add(null);
            }

            return _list;
        }

        private List<double?> GetScoreCardDoubleListForCharting(string column)
        {
            List<double?> _list = new List<double?>();

            for (int x = 0; x < _scoreCardMetrics.Rows.Count; x++)
            {
                object ID = _scoreCardMetrics.Rows[x][column];
                if (ID != null && !String.IsNullOrEmpty(ID.ToString().Trim()))
                    _list.Add((double)ID);
                else
                    _list.Add(null);
            }

            return _list;
        }

        private List<Single?> GetScoreCardSingleListForCharting(string column)
        {
            List<Single?> _list = new List<Single?>();

            for (int x = 0; x < _scoreCardMetrics.Rows.Count; x++)
            {
                object ID = _scoreCardMetrics.Rows[x][column];
                if (ID != null && !String.IsNullOrEmpty(ID.ToString().Trim()))
                    _list.Add((Single)ID);
                else
                    _list.Add(null);
            }

            return _list;
        }

        private List<string> GetScoreCardStringListForCharting(string column)
        {
            List<string> _list = new List<string>();

            for (int x = 0; x < _scoreCardMetrics.Rows.Count; x++)
            {
                object ID = _scoreCardMetrics.Rows[x][column];
                if (ID != null && !String.IsNullOrEmpty(ID.ToString().Trim()))
                    _list.Add((string)ID);
                else
                    _list.Add("");
            }

            return _list;
        }
        #endregion

        #region -- Scorecard Chart Goal methods ------------------------------------------------------------------------------------------
        private void AddScorecardGoalObjectToChart(ref Chart chart, string name, string color, string goalValue, bool higherIsBetter)
        {
            double goalValueToUse;
            double.TryParse(goalValue, out goalValueToUse);
            System.Drawing.Color seriesColor = (System.Drawing.Color)TypeDescriptor.GetConverter(typeof(System.Drawing.Color)).ConvertFromString(color);
            AddScorecardGoalObjectToChart(ref chart, name, seriesColor, goalValueToUse, higherIsBetter, false);
        }

        private void AddScorecardGoalObjectToChart(ref Chart chart, string name, System.Drawing.Color color, double goalValueToUse, bool higherIsBetter, bool isSingleItemChart)
        {

            Series series = new Series();
            series.ChartType = SeriesChartType.Area;

            if(isSingleItemChart)
            {
                System.Drawing.Color seriesColor;
                System.Drawing.Color backColor;
                if (higherIsBetter) //Green is above the line
                {
                    seriesColor = System.Drawing.Color.Red;
                    backColor = System.Drawing.Color.Green;
                }
                else
                {
                    seriesColor = System.Drawing.Color.Green;
                    backColor = System.Drawing.Color.Red;
                }
                // Make the color semi-transparent
                series.Color = System.Drawing.Color.FromArgb(128, seriesColor.R, seriesColor.G, seriesColor.B);
                series.BackSecondaryColor = System.Drawing.Color.FromArgb(128, backColor.R, backColor.G, backColor.B);
                series.YAxisType = AxisType.Primary;
            }
            else
            {
                System.Drawing.Color seriesColor = color;
                // Make the color semi-transparent
                series.Color = System.Drawing.Color.FromArgb(128, seriesColor.R, seriesColor.G, seriesColor.B);
                series.BackGradientStyle = GradientStyle.TopBottom;
                series.BackSecondaryColor = System.Drawing.Color.Transparent;
                series.YAxisType = AxisType.Secondary;
            }
            series.Name = name;
            series.XAxisType = AxisType.Secondary;
            series.IsVisibleInLegend = false;

            int numDataPoints = chart.Series[0].Points.Count + 1; // add extra point to allow these to offset against the normal points
            for (int x = 0; x < numDataPoints; x++)
            {
                series.Points.Add(new DataPoint
                {
                    YValues = new double[] { goalValueToUse }
                });
            }
            chart.Series.Insert(0, series);
            
            if(!isSingleItemChart)
            { 
                string higherLower = higherIsBetter ? ">" : "<";
                string goalLineString = String.Format("Goal Line\r\n{0} {1} {2}", higherLower, goalValueToUse, name);
                AddScorecardGoalAnnotations(ref chart, 0, numDataPoints - 1, goalLineString);
            }
        }

        private void AddScorecardGoalAnnotations(ref Chart chart, int seriesId, int pointId, string text)
        {
            // Create a callout annotation
            CalloutAnnotation annotation = new CalloutAnnotation();

            // Setup visual attributes
            annotation.CalloutStyle = CalloutStyle.RoundedRectangle;
            annotation.ShadowOffset = 2;
            annotation.ShadowColor = System.Drawing.Color.Silver;
            annotation.IsMultiline = true;
            annotation.AnchorDataPoint = chart.Series[seriesId].Points[pointId];
            annotation.Text = text;
            annotation.Font = new System.Drawing.Font("Calibri", 22, System.Drawing.FontStyle.Bold);
            annotation.BackColor = System.Drawing.Color.FromArgb(255, 255, 224, 192);
            annotation.LineColor = System.Drawing.Color.Black;
            annotation.AnchorAlignment = System.Drawing.ContentAlignment.BottomRight;

            // Add the annotation to the collection
            chart.Annotations.Add(annotation);
        }
        #endregion
    }
}
